﻿using System;
using System.Globalization;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using VMExplorer.MemoryObjects;
using VMExplorer.Win32;

namespace VMExplorer.Forms
{
  partial class ReportForm : Form
  {
    public ReportForm(VMEDocument doc)
    {
      InitializeComponent();



      StringBuilder sb = new StringBuilder();

      sb.AppendFormat("Memory analysis report generated on {0}", DateTime.Now.ToString("r", CultureInfo.CreateSpecificCulture("en-US"))); sb.AppendLine();
      sb.AppendFormat("with {0} version {1}", Assembly.GetExecutingAssembly().GetName().Name, Assembly.GetExecutingAssembly().GetName().Version); sb.AppendLine();


      #region :: Summary ::

      {
        uint total = 0;
        uint busy = 0;
        uint[] usage = new uint[Enum.GetValues(typeof(RegionUsage)).Length];
        uint[] type = new uint[Enum.GetValues(typeof(Native.PAGE_TYPE)).Length];
        uint[] state = new uint[Enum.GetValues(typeof(Native.PAGE_STATE)).Length];

        foreach (RegionInfo ri in doc.AddressRanges)
        {
          usage[(int)ri.Usage] += ri.Size;

          if ((ri.Type & Native.PAGE_TYPE.MEM_IMAGE) != 0) type[0] += ri.Size;
          if ((ri.Type & Native.PAGE_TYPE.MEM_MAPPED) != 0) type[1] += ri.Size;
          if ((ri.Type & Native.PAGE_TYPE.MEM_PRIVATE) != 0) type[2] += ri.Size;

          if ((ri.State & Native.PAGE_STATE.MEM_COMMIT) != 0) state[0] += ri.Size;
          if ((ri.State & Native.PAGE_STATE.MEM_RESERVE) != 0) state[1] += ri.Size;
          if ((ri.State & Native.PAGE_STATE.MEM_FREE) != 0) state[2] += ri.Size;

          total += ri.Size;
          if (ri.Usage != RegionUsage.Free) busy += ri.Size;
        }

        sb.AppendLine();
        sb.AppendFormat(":: Summary ::"); sb.AppendLine();

        sb.AppendLine();
        sb.AppendFormat("               Type |  Total size  |  pct (total) |  pct (busy)  "); sb.AppendLine();
        sb.AppendFormat("  ------------------+--------------+--------------+--------------"); sb.AppendLine();
        sb.AppendFormat("               Free | {0,8} kB  |    {1:00.00}%    |    {2:00.00}%    ", state[2] / 1024.0f, 100.0f * state[2] / total, 0); sb.AppendLine();
        sb.AppendFormat("          Committed | {0,8} kB  |    {1:00.00}%    |    {2:00.00}%    ", state[0] / 1024.0f, 100.0f * state[0] / total, 100.0f * state[0] / busy); sb.AppendLine();
        sb.AppendFormat("           Reserved | {0,8} kB  |    {1:00.00}%    |    {2:00.00}%    ", state[1] / 1024.0f, 100.0f * state[1] / total, 100.0f * state[1] / busy); sb.AppendLine();
        sb.AppendFormat("  ------------------+--------------+--------------+--------------"); sb.AppendLine();
        sb.AppendFormat("            Private | {0,8} kB  |    {1:00.00}%    |    {2:00.00}%    ", type[2] / 1024.0f, 100.0f * type[2] / total, 100.0f * type[2] / busy); sb.AppendLine();
        sb.AppendFormat("            Modules | {0,8} kB  |    {1:00.00}%    |    {2:00.00}%    ", type[0] / 1024.0f, 100.0f * type[0] / total, 100.0f * type[0] / busy); sb.AppendLine();
        sb.AppendFormat("             Mapped | {0,8} kB  |    {1:00.00}%    |    {2:00.00}%    ", type[1] / 1024.0f, 100.0f * type[1] / total, 100.0f * type[1] / busy); sb.AppendLine();

        sb.AppendLine();
        sb.AppendFormat("              Usage |  Total size  |  pct (total) |  pct (busy)  "); sb.AppendLine();
        sb.AppendFormat("  ------------------+--------------+--------------+--------------"); sb.AppendLine();
        for (int i = 0; i < usage.Length; i++)
        {
          sb.AppendFormat("   {0,16} | {1,8} kB  |    {2:00.00}%    |    {3:00.00}%    ", (RegionUsage)i, usage[i] / 1024.0f, 100.0f * usage[i] / total, ((RegionUsage)i != RegionUsage.Free) ? 100.0f * usage[i] / busy : 0); sb.AppendLine();
        }
      }
      #endregion

      #region :: Modules ::

      {
        uint nbModules = 0;
        uint totalReserved = 0;
        uint totalCommited = 0;
        StringBuilder sbModules = new StringBuilder();

        foreach (IMemoryObject mo in doc.MemoryObjects)
        {
          ModuleObject pmw = mo as ModuleObject;
          if (pmw == null) continue;

          uint reserved = pmw.Stats.ReservedBytes;
					uint commited = pmw.Stats.CommittedBytes;
          uint total = commited + reserved;

          totalCommited += commited;
          totalReserved += reserved;
          nbModules++;


          sbModules.AppendLine();
          sbModules.AppendFormat("{0:X8} {1:X8}  {2}", pmw.BaseAddress, pmw.BaseAddress + total, pmw.Name); sbModules.AppendLine();
          sbModules.AppendFormat("        Total bytes: {0}", total); sbModules.AppendLine();
          sbModules.AppendFormat("    Committed bytes: {0}", commited); sbModules.AppendLine();
          sbModules.AppendFormat("     Reserved bytes: {0}", reserved); sbModules.AppendLine();
          sbModules.AppendFormat("         Image path: {0}", pmw.ModulePath); sbModules.AppendLine();
          sbModules.AppendFormat("         Time Stamp: {0}", pmw.TimeDateStamp); sbModules.AppendLine();
        }

        sb.AppendLine();
        sb.AppendFormat(":: Modules ::"); sb.AppendLine();
        sb.AppendLine();
        sb.AppendFormat("{0} modules loaded", nbModules); sb.AppendLine();
        sb.AppendLine();
        sb.AppendFormat("  {0,8} kB commited", (float)totalCommited / 1024.0f); sb.AppendLine();
        sb.AppendFormat("  {0,8} kB reserved", (float)totalReserved / 1024.0f); sb.AppendLine();
        sb.AppendFormat("  --------"); sb.AppendLine();
        sb.AppendFormat("  {0,8} kB of virtual memory used", (float)(totalCommited + totalReserved) / 1024.0f); sb.AppendLine();
        sb.AppendLine();
        sb.Append(sbModules);
        sb.AppendLine();
      }

      #endregion

      #region :: Heaps ::

      {
        uint nbHeaps = 0;
        uint totalCommited = 0;
        uint totalReserved = 0;
        uint totalVAllocd = 0;
        StringBuilder sbHeaps = new StringBuilder();

        foreach (IMemoryObject mo in doc.MemoryObjects)
        {
          HeapObject hw = mo as HeapObject;
          if (hw == null) continue;

          uint reserved = 0;
          uint commited = 0;
          uint vallocd = 0;
          uint nbSegments = 1;
          uint nbVAllocd = 0;


					commited += hw.Stats.CommittedBytes;
					reserved += hw.Stats.ReservedBytes;
          nbHeaps++;

          StringBuilder sbSegments = new StringBuilder();
          foreach (HeapSegmentObject hsw in hw.SegmentList)
          {
						uint reservedSegment = hsw.Stats.ReservedBytes;
						uint commitedSegment = hsw.Stats.CommittedBytes;
						uint fragments = hsw.Stats.Fragments;

            sbSegments.AppendFormat("         Segment #{0}: {1} fragment{2}, {3} commited bytes, {4} reserved bytes",
              nbSegments, 
              fragments, 
              fragments > 1 ? "s" : string.Empty,
              commitedSegment,
              reservedSegment); sbSegments.AppendLine();

            commited += commitedSegment;
            reserved += reservedSegment;
            nbSegments++;
          }

          StringBuilder sbVallocd = new StringBuilder();
          foreach (HeapVirtualAllocdObject hvaw in hw.VallocdList)
          {
						uint vallocdSegment = hvaw.Stats.TotalBytes;

            sbVallocd.AppendFormat("         Vallocd #{0}: {1} bytes", nbVAllocd, vallocdSegment); sbSegments.AppendLine();

            vallocd += vallocdSegment;
            nbVAllocd ++;
          }

          totalCommited += commited;
          totalReserved += reserved;
          totalVAllocd += vallocd;

          sbHeaps.AppendLine();
          sbHeaps.AppendFormat("{0:X8} {1} : {2} segment{3}, {4} vallocd{5}", hw.BaseAddress, hw.Name, nbSegments, nbSegments > 1 ? "s" : string.Empty, nbVAllocd, nbVAllocd > 1 ? "s" : string.Empty); sbHeaps.AppendLine();
          sbHeaps.AppendFormat("    Committed bytes: {0}", commited); sbHeaps.AppendLine();
          sbHeaps.AppendFormat("     Reserved bytes: {0}", reserved); sbHeaps.AppendLine();
          sbHeaps.AppendFormat("      VAllocd bytes: {0}", vallocd); sbHeaps.AppendLine();
          sbHeaps.Append(sbSegments.ToString());
          sbHeaps.Append(sbVallocd.ToString());
        }

        sb.AppendLine();
        sb.AppendFormat(":: Heaps ::"); sb.AppendLine();
        sb.AppendLine();
        sb.AppendFormat("{0} heaps", nbHeaps); sb.AppendLine();
        sb.AppendLine();
        sb.AppendFormat("  {0,8} kB commited", (float)totalCommited / 1024.0f); sb.AppendLine();
        sb.AppendFormat("  {0,8} kB reserved", (float)totalReserved / 1024.0f); sb.AppendLine();
        sb.AppendFormat("  {0,8} kB vallocd", (float)totalVAllocd / 1024.0f); sb.AppendLine();
        sb.AppendFormat("  --------"); sb.AppendLine();
        sb.AppendFormat("  {0,8} kB of virtual memory used", (float)(totalCommited + totalReserved + totalVAllocd) / 1024.0f); sb.AppendLine();
        sb.AppendLine();
        sb.Append(sbHeaps);
        sb.AppendLine();
      }

      #endregion

      textBox1.Text = sb.ToString();
    }
  }
}
